package ar.uba.fi.tonyvaliente.utils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Delta {
	
	public static byte[] encode(List<Integer> decimals) {

		int[] decimalsArray = new int[decimals.size()];
		
		int i = 0;
		for (Integer decimal : decimals) {
			decimalsArray[i] = decimal;
			i++;
		}
		
		return encode(decimalsArray);
	}
	
	public static List<Integer> decodeToList(byte[] delta) {
		int[] decimalsArray = decode(delta);
		List<Integer> decimals = new ArrayList<Integer>();
		
		for (int i = 0; i < decimalsArray.length; i++) {
			decimals.add(decimalsArray[i]);
		}
		return decimals;
	}
	
	public static byte[] encode(int[] decimals) {
		StringBuffer buffer = new StringBuffer();
		for (int i = 0; i < decimals.length; i++) {
			buffer.append(encode(decimals[i]));
		}
		while (buffer.length() % 8 != 0) {
			buffer.append('0');
		}

		byte[] result = new byte[buffer.length() / 8];
		for (int b = 0; b < result.length; b++) {
			int byt = 0;
			for (int i = b * 8, p = 7; i < (b + 1) * 8; i++, p--) {
				if (buffer.charAt(i) == '1') {
					byt += Math.pow(2, p);
				}
			}
			Integer intByte = new Integer(byt);
			result[b] = intByte.byteValue();
		}
		return result;
	}

	private static String encode(int decimal) {
		String binary = Integer.toBinaryString(decimal);

		String y = binary.substring(1);
		String x = Integer.toBinaryString(binary.length());
		StringBuffer bBuffer = new StringBuffer();
		for (int i = 0; i < x.length() - 1; i++)
			bBuffer.append('0');
		String b = bBuffer.toString();

		StringBuffer buffer = new StringBuffer();
		buffer.append(b);
		buffer.append(x);
		buffer.append(y);
		return buffer.toString();
	}

	public static int[] decode(byte[] delta) {
		StringBuffer buffer = new StringBuffer();
		for (int b = 0; b < delta.length; b++) {
			int i = new Integer(delta[b]).intValue();
			if (i < 0)
				i += 256;
			String bits = Integer.toBinaryString(i);
			int l = buffer.length() + bits.length();
			while (l % 8 != 0) {
				buffer.append('0');
				l++;
			}
			buffer.append(bits);
		}

		int resultLength = 0;
		LinkedList<Integer> decimals = new LinkedList<Integer>();
		int ci = 0;
		while (ci < buffer.length()) {
			if (buffer.length() == 0)
				break;

			int b = 0, ib = ci;
			while (buffer.charAt(ib) == '0') {
				b++;
				ib++;

				if (ib == buffer.length())
					break;
			}
			if (ib == buffer.length())
				break;

			int x = 0, ix = ib--, ixm = ix + b + 1;
			while (ix < ixm) {
				if (ix == buffer.length())
					break;

				if (buffer.charAt(ix) == '1')
					x += Math.pow(2, b);
				b--;
				ix++;
			}
			if (ix == buffer.length())
				break;

			int y = (int) Math.pow(2, --x), iy = ix--, iym = iy + x;
			while (iy < iym) {
				if (iy == buffer.length())
					break;

				x--;
				if (buffer.charAt(iy) == '1')
					y += Math.pow(2, x);
				iy++;
			}

			decimals.add(new Integer(y));
			resultLength++;
			ci = iy--;
		}

		int[] result = new int[resultLength];
		int i = 0;
		for (Integer integer : decimals)
			result[i++] = integer.intValue();
		return result;
	}
}
